package _go

/*剑指 Offer 09. 用两个栈实现队列
难度
简单

333

收藏

分享
切换为英文
接收动态
反馈
用两个栈实现一个队列。队列的声明如下，请实现它的两个函数 appendTail 和 deleteHead ，分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素，deleteHead 操作返回 -1 )



示例 1：

输入：
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出：[null,null,3,-1]
示例 2：

输入：
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出：[null,-1,null,null,5,2]
提示：

1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用
*/
import (
	"sync"
)

type CQueue struct {
	IStark Stack
	OStark Stack
}

//定义一个栈的结构体
type Stack struct {
	S []int
}

//栈的push方法
func (s *Stack) Push(value int) {
	s.S = append(s.S, value)
}

//栈的pop方法
func (s *Stack) Pop() (res int) {
	l := len(s.S)
	if l <= 0 {
		return
	}
	rw := sync.RWMutex{}
	rw.Lock()
	defer rw.Unlock()
	res = s.S[l-1]

	s.S = s.S[:l-1]
	return
}

//其实还应该有一个peek方法 返回栈顶的元素值
func (s *Stack) Peek() int {
	return s.S[len(s.S)-1]
}

//所有的写操作应该有锁
func Constructor() CQueue {
	return CQueue{}
}

func (this *CQueue) AppendTail(value int) {
	//入就直接让入栈的栈中压入一个即可 把切片的最后一个人当成栈的最上边
	this.IStark.Push(value)
}

//删除元素需要判断一下出栈的个数是否为空 不空直接删除 空的话需要判断一下入栈是否为空 为空直接返回报错 不空需要将入栈的数据顺序pop到出栈里面
func (this *CQueue) DeleteHead() int {
	if len(this.OStark.S) == 0 {
		if len(this.IStark.S) == 0 {
			return -1
		} else {
			//把入的数据写入到 出栈里面  在删除最上边的元素返回
			//这里也需要锁
			for range this.IStark.S {
				this.OStark.Push(this.IStark.Pop())
			}
		}
	}
	//到这就说明出栈还有值 直接返回值
	return this.OStark.Pop()
}

/**
 * Your CQueue object will be instantiated and called as such:
 * obj := Constructor();
 * obj.AppendTail(value);
 * param_2 := obj.DeleteHead();
 */
